package cn.initcap.designpattern.pattern.behavioral.strategy;

import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
import org.reflections.Reflections;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;

/**
 * @author initcap
 * @date Created in 2020/5/7 16:42.
 */
public class AnnotationStrategyFactory {

    private static Map<StrategyType, PromotionStrategy> registerMap = new EnumMap<>(StrategyType.class);

    static {
        registerStrategy();
    }

    private AnnotationStrategyFactory() {
        throw new IllegalArgumentException("Utility class.");
    }

    /**
     * 通过map获取策略，当增加新的策略时无需修改代码，开闭原则
     *
     * @param strategyType
     * @return
     */
    public static PromotionStrategy getStrategy(StrategyType strategyType) {
        if (registerMap.containsKey(strategyType)) {
            return registerMap.get(strategyType);
        } else {
            throw new RuntimeException("The strategy type is not supported.");
        }
    }

    /**
     * 自动注册策略
     */
    private static void registerStrategy() {
        try {
            // 通过反射找到所有的策略
            Reflections reflections = new Reflections(new ConfigurationBuilder()
                    .setUrls(ClasspathHelper.forPackage(PromotionStrategy.class.getPackage().getName()))
                    .setScanners(new SubTypesScanner()));
            Set<Class<? extends PromotionStrategy>> promotionStrategyClassSet = reflections.getSubTypesOf(PromotionStrategy.class);

            if (promotionStrategyClassSet != null) {
                for (Class<?> clazz : promotionStrategyClassSet) {
                    // 找到策略类型注解，自动完成策略注册
                    if (clazz.isAnnotationPresent(StrategyTypeAnnotation.class)) {
                        StrategyTypeAnnotation strategyTypeAnnotation = clazz.getAnnotation(StrategyTypeAnnotation.class);
                        StrategyType strategyType = strategyTypeAnnotation.strategyType();
                        registerMap.put(strategyType, (PromotionStrategy) clazz.newInstance());
                    }
                }
            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

}
